package com.mng.index12306.biz.gatewayservice.filter;

import com.mng.index12306.biz.gatewayservice.config.Config;
import com.mng.index12306.biz.gatewayservice.toolkit.JWTUtil;
import com.mng.index12306.biz.gatewayservice.toolkit.UserInfoDTO;
import com.mng.index12306.framework.starter.bases.constant.UserConstant;
import io.jsonwebtoken.lang.Collections;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

/**
 * @Description : Spring gateway Token 拦截器 * @Author : YuShaochao
 * @Date : 2024-05-15 14:46
 */
@Component
public class TokenValidateGatewayFilterFactory extends AbstractGatewayFilterFactory<Config> {

    public TokenValidateGatewayFilterFactory() {
        super(Config.class);
    }

    /**
     * 注销用户时需要传递 Token
     */
    public static final String DELETION_PATH = "/api/user-service/deletion";

    @Override
    public GatewayFilter apply(Config config) {
        return (ServerWebExchange exchange, GatewayFilterChain chain) ->{
            ServerHttpRequest request = exchange.getRequest();
            String requestPath = request.getPath().toString();
            if( isPathInBlackPreList(requestPath, config.getBlackPathPre())){
                String token = request.getHeaders().getFirst("Authorization");
                UserInfoDTO userInfo = JWTUtil.parseJwtToken(token);
                if(!validateToken(userInfo)){
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.UNAUTHORIZED);
                    return response.setComplete();
                }
                ServerHttpRequest.Builder builder = exchange.getRequest().mutate().headers( httpHeaders -> {
                    httpHeaders.set(UserConstant.USER_ID_KEY, userInfo.getUserId());
                    httpHeaders.set(UserConstant.USER_NAME_KEY, userInfo.getUsername());
                    httpHeaders.set(UserConstant.REAL_NAME_KEY, URLEncoder.encode(userInfo.getRealName(), StandardCharsets.UTF_8));
                    if (Objects.equals(requestPath, DELETION_PATH)){
                        httpHeaders.set(UserConstant.USER_TOKEN_KEY,token);
                    }
                });
                return chain.filter(exchange.mutate().request(builder.build()).build());
            }
            return chain.filter(exchange);
        };
    }


    private boolean isPathInBlackPreList(String requestPath, List<String> blackPathPre){
        if (Collections.isEmpty(blackPathPre)){
            return false;
        }
        return blackPathPre.stream().anyMatch(requestPath::startsWith);
    }

    private boolean validateToken(UserInfoDTO userInfo){
        return userInfo != null;
    }


}
